package com.hyzx.qbasic.admin.domain.service.impl;

import com.google.common.io.Files;
import com.hyzx.qbasic.admin.domain.service.IPoiService;
import com.hyzx.qbasic.admin.model.constant.CommonConst;
import com.hyzx.qbasic.common.util.DateUtils;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.usermodel.Range;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;

/**
 * Created by 黄江华 on 2018/8/21
 */

@Service
public class PoiServiceImpl implements IPoiService {
    private static final Logger logger = LoggerFactory.getLogger(PoiServiceImpl.class);

    @Override
    public void exportWordToFile(String templateFileUrl, Map<String, String> contentMap, File exportFile) {
        try {
            // 打开word模板文件
            InputStream templateFileInputStream = this.getClass().getClassLoader().getResourceAsStream(templateFileUrl);
            //创建POI文档对象
            HWPFDocument document = new HWPFDocument(templateFileInputStream);
            // 读取word模板文件内容
            Range bodyRange = document.getRange();
            // 替换模板文件中的标签为实际内容
            for (Map.Entry<String, String> entry : contentMap.entrySet()) {
                bodyRange.replaceText("${" + entry.getKey() + "}", entry.getValue());
            }

            document.write(exportFile);
            document.close();
            templateFileInputStream.close();
        } catch (FileNotFoundException ex) {
            logger.error("导出word文档失败，模板文件不存在", ex);
        } catch (IOException ex) {
            logger.error("导出word文档失败，创建POI文档对象异常", ex);
        } catch (Exception ex) {
            logger.error("导出word文档失败", ex);
        }
    }

    @Override
    public void exportWordToResponse(String templateFileUrl, String fileName, Map<String, String> contentMap, HttpServletResponse response) {
        try {
            // 导出临时文件
            File tempFile = File.createTempFile(fileName, ".doc");
            exportWordToFile(templateFileUrl, contentMap, tempFile);

            //构造响应头
            String fullFileName = fileName + ".doc";
            response.setHeader("Content-Disposition", "attachment;filename*=UTF-8''" + URLEncoder.encode(fullFileName, "UTF-8"));
            response.addHeader("Content-Length", "" + tempFile.length());
            response.setContentType("application/octet-stream;charset=UTF-8");

            // 读取临时文件到内存，并删除临时文件
            byte[] data = Files.toByteArray(tempFile);
            tempFile.delete();

            // 输出response
            OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
            outputStream.write(data);
            outputStream.flush();
            outputStream.close();
        } catch (Exception ex) {
            logger.error("导出word文档失败", ex);
        }
    }

    @Override
    public HSSFWorkbook getWorkbook(String templateFileUrl) {
        HSSFWorkbook workbook = null;

        try {
            // 打开excel模板文件
            InputStream templateFileInputStream = this.getClass().getClassLoader().getResourceAsStream(templateFileUrl);
            //创建Excel工作簿对象
            workbook = new HSSFWorkbook(templateFileInputStream);
            templateFileInputStream.close();
        } catch (FileNotFoundException ex) {
            logger.error("导出excel文档失败，模板文件不存在", ex);
        } catch (IOException ex) {
            logger.error("导出excel文档失败，创建POI文档对象异常", ex);
        }

        return workbook;
    }

    @Override
    public void exportExcelTitleRow(HSSFWorkbook workbook, int sheetIndex, List<String> titles, int offset) {
        try {
            //打开工作表
            HSSFSheet sheet = workbook.getSheetAt(sheetIndex);

            if (CollectionUtils.isNotEmpty(titles)) {
                HSSFRow row = sheet.createRow(offset);
                for (int i = 0; i < titles.size(); i++) {
                    String title = titles.get(i);
                    HSSFCell cellTitle = row.createCell(i);
                    cellTitle.setCellValue(title);
                }
            }
        } catch (Exception ex) {
            logger.error("导出excel文档标题行失败", ex);
        }
    }

    @Override
    public <T> void exportEntityToExcel(HSSFWorkbook workbook, int sheetIndex, List<String> cols, int offset, List<T> data) {
        try {
            //打开工作表
            HSSFSheet sheet = workbook.getSheetAt(sheetIndex);

            for (int i = 0; i < data.size(); i++) {
                HSSFRow row = sheet.createRow(offset + i);
                T entity = data.get(i);

                for (int j = 0; j < cols.size(); j++) {
                    HSSFCell cell = row.createCell(j);

                    String value = BeanUtils.getProperty(entity, cols.get(j));
                    if (NumberUtils.isDigits(value)) {
                        cell.setCellValue(NumberUtils.createDouble(value));
                    } else {
                        String formattedStr = tryParseDate(value);
                        if (StringUtils.isNotEmpty(formattedStr)) {
                            cell.setCellValue(formattedStr);
                        } else {
                            cell.setCellValue(value);
                        }
                    }
                }
            }
        } catch (Exception ex) {
            logger.error("导出excel文档失败", ex);
        }
    }

    @Override
    public void exportMapToExcel(HSSFWorkbook workbook, int sheetIndex, List<String> cols, int offset, List<Map<String, Object>> data) {
        try {
            //打开工作表
            HSSFSheet sheet = workbook.getSheetAt(sheetIndex);

            for (int i = 0; i < data.size(); i++) {
                HSSFRow row = sheet.createRow(offset + i);
                Map<String, Object> entity = data.get(i);

                for (int j = 0; j < cols.size(); j++) {
                    Object val = entity.get(cols.get(j));

                    String value;
                    if (val == null)
                        value = StringUtils.EMPTY;
                    else if (val instanceof Date)
                        value = DateUtils.parseToString((Date) val);
                    else
                        value = val.toString();

                    HSSFCell cell = row.createCell(j);
                    cell.setCellValue(value);
                }
            }
        } catch (Exception ex) {
            logger.error("导出excel文档失败", ex);
        }
    }

    @Override
    public void exportExcelToResponse(HSSFWorkbook workbook, String fileName, HttpServletResponse response) {
        try {
            // 导出临时文件
            File tempFile = File.createTempFile(fileName, ".xls");

            workbook.write(tempFile);
            workbook.close();

            //构造响应头
            String fullFileName = fileName + ".xls";
            response.setHeader("Content-Disposition", "attachment;filename*=UTF-8''" + URLEncoder.encode(fullFileName, "UTF-8"));
            response.addHeader("Content-Length", "" + tempFile.length());
            response.setContentType("application/vnd.ms-excel;charset=UTF-8");

            // 读取临时文件到内存，并删除临时文件
            byte[] bytes = Files.toByteArray(tempFile);
            tempFile.delete();

            // 输出response
            OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
            outputStream.write(bytes);
            outputStream.flush();
            outputStream.close();
        } catch (Exception ex) {
            logger.error("导出excel文档失败", ex);
        }
    }

    private String tryParseDate(String str) {
        Date date = null;
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(CommonConst.DATE_FORMAT_ENGLISH, Locale.ENGLISH);
            date = sdf.parse(str);
        } catch (Exception ex) {
        }

        if (date != null) {
            String formatDate = new SimpleDateFormat(CommonConst.STANDARD_DATE_FORMAT).format(date);
            return formatDate;
        }

        return null;
    }
}
